package com.github.cyf.util;

import org.apache.ibatis.mapping.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 创建新的 MappedStatement
 * @author chenyifan
 * @create 2024-04-13 21:49
 */
public class MSUtil {

    public static final String COUNT = "_COUNT";
    private static final List<ResultMapping> EMPTY_RESULT_MAPPING = new ArrayList<>(0);

    public static Method getMapperMethod(MappedStatement ms) {
        String msId = ms.getId();
        String className = msId.substring(0, msId.lastIndexOf("."));
        String methodName = msId.substring(msId.lastIndexOf(".") + 1);
        Method method = null;
        try {
            Method[] methods = Class.forName(className).getMethods();
            for (Method m : methods) {
                if (m.getName().equals(methodName)) {
                    method = m;
                    break;
                }
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return method;
    }

    /**
     * 新建 count 查询的 MappedStatement
     * 主要是复制 MappedStatement 的配置信息及自定义 resultMap
     * @param ms
     * @param countMsId
     * @param countSql 查询分页数量的 sql
     * @param parameterMappings 参数映射
     * @return
     */
    public static MappedStatement newCountMappedStatement(MappedStatement ms, String countMsId, String countSql, List<ParameterMapping> parameterMappings) {
        // 复制 MappedStatement 的配置信息，但是 sqlSource 需要自定义
        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), countMsId,
                new SqlSource() {
                    @Override
                    public BoundSql getBoundSql(Object parameterObject) {
                        return new BoundSql(ms.getConfiguration(), countSql, parameterMappings, parameterObject);
                    }
                }, ms.getSqlCommandType()
        );
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        /**
         * 这里为什么这样写可以参考源码，keyProperty 方法最终会调用如下方法，将返回的字符串数组赋值给 keyProperties
         * {@link org.apache.ibatis.mapping.MappedStatement#delimitedStringToArray}
         */
        builder.keyProperty(String.join(",", ms.getKeyProperties()));
        // 设置 resultMap
        List<ResultMap> resultMaps = new ArrayList<ResultMap>();
        // count 查询返回值 int
        ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), countMsId, int.class, EMPTY_RESULT_MAPPING).build();
        resultMaps.add(resultMap);
        builder.resultMaps(resultMaps);
        return builder.build();
    }

    /**
     * 新建count查询的MappedStatement
     *
     * @param ms
     * @return
     */
    public static MappedStatement newCountMappedStatement(MappedStatement ms, String countSql, List<ParameterMapping> parameterMappings) {
        return newCountMappedStatement(ms, ms.getId() + COUNT, countSql, parameterMappings);
    }
}
